#include "StdAfx.h"
#include "GTDListCtrl.h"
#include <algorithm>
#include "InPlaceEdit.h"
#include "../core/cpputil.h"

BEGIN_MESSAGE_MAP(CGTDListCtrl, CListCtrl)
	ON_WM_LBUTTONDBLCLK()	
	ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndlabeledit)
	ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnClickColumn)
	ON_WM_CHAR()
END_MESSAGE_MAP()




//ListCtrlItemImpl* CGTDListCtrl::GetItemImpl( int nItem, int nSubItem ) const
//{
//	ItemImplMap* pMap = GetImplMap(nItem);
//	if(!pMap)
//		return NULL;
//
//	ItemImplMap::const_iterator itr = pMap->find(nSubItem);
//	if(itr!=pMap->end())
//	{
//		return itr->second;
//	}
//	return NULL;
//}
//
//void CGTDListCtrl::SetItemImpl( int nItem, int nSubItem, ListCtrlItemImpl* impl,bool bManageDel)
//{
//	ItemImplMap* pMap = GetImplMap(nItem);
//	ASSERT(pMap);
//
//	(*pMap)[nSubItem] = impl;
//	if(impl)
//	{
//		impl->OnSetTo(*this,nItem,nSubItem);
//		if(bManageDel)
//			AddManageImp(impl);
//	}
//}

int CGTDListCtrl::HitTestEx( CPoint& point, int* col )
{
	int colnum = 0;
	int row = HitTest(point, NULL);

	if(col) 
		*col = 0;

	// Make sure that the ListView is in LVS_REPORT
	if((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
		return row;

	// Get the number of columns
	CHeaderCtrl* pHeader = GetHeaderCtrl();
	int nColumnCount = pHeader->GetItemCount();

	// Get the top and bottom row visible
	row = GetTopIndex();

	int bottom = row + GetCountPerPage();
	if(bottom > GetItemCount())
		bottom = GetItemCount();

	// Loop through the visible rows
	for( ;row <=bottom; row++)
	{
		// Get bounding rect of item and check whether point falls in it.
		CRect rect;
		if( GetItemRect(row, &rect, LVIR_BOUNDS) )
		{
			if( rect.PtInRect(point) )
			{
				// Now find the column
				for( colnum = 0; colnum < nColumnCount; colnum++ )
				{
					int colwidth = GetColumnWidth(colnum);
					if(point.x >= rect.left && point.x <= (rect.left + colwidth))
					{
						if(col) 
							*col = colnum;
						return row;
					}
					rect.left += colwidth;
				}
			}
		}		
	}
	return -1;
}

CEdit* ListCtrlItemImpl::ShowInPlaceEdit(CGTDListCtrl& ctrl, int nItem, int nCol, const CString& s )
{
	// The returned pointer should not be saved

	// Make sure that the item is visible
	if(!ctrl.EnsureVisible(nItem, TRUE)) 
		return NULL;

	// Make sure that nCol is valid
	CHeaderCtrl* pHeader = ctrl.GetHeaderCtrl();
	int nColumnCount = pHeader->GetItemCount();
	if(nCol >= nColumnCount || ctrl.GetColumnWidth(nCol) < 5)
		return NULL;

	// Get the column offset
	int offset = 0;
	for(int i = 0; i < nCol; i++)
		offset += ctrl.GetColumnWidth(i);

	CRect rect;
	ctrl.GetItemRect(nItem, &rect, LVIR_BOUNDS);

	// Now scroll if we need to expose the column
	CRect rcClient;
	ctrl.GetClientRect(&rcClient);
	if(offset + rect.left < 0 || offset + rect.left > rcClient.right)
	{
		CSize size;
		size.cx = offset + rect.left;
		size.cy = 0;
		ctrl.Scroll(size);
		rect.left -= size.cx;
	}
	// Get Column alignment
	LV_COLUMN lvcol;
	lvcol.mask = LVCF_FMT;
	ctrl.GetColumn(nCol, &lvcol);
	DWORD dwStyle ;
	if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
		dwStyle = ES_LEFT;
	else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
		dwStyle = ES_RIGHT;
	else dwStyle = ES_CENTER;

	rect.left += offset+4;
	rect.right = rect.left + ctrl.GetColumnWidth(nCol) - 3 ;
	if(rect.right > rcClient.right) 
		rect.right = rcClient.right;

	dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;


	CInPlaceEdit *pEdit = new CInPlaceEdit(nItem,nCol,s);
	pEdit->Create( dwStyle, rect, &ctrl,  0);
	return pEdit;
}


int CGTDListCtrl::GetSelectedItems( IntList& itemlist ) const
{	
	int nCount=0;
	POSITION   pos   =   GetFirstSelectedItemPosition();   
	if   (pos   ==   NULL)   
		TRACE0("No   items   were   selected!\n");   
	else   
	{   
		while   (pos)   
		{   
			int   nItem   =   GetNextSelectedItem(pos);   
			TRACE1("Item   %d   was   selected!\n",   nItem);   
			//   you   could   do   your   own   processing   on   nItem   here 
			itemlist.push_back(nItem);
			nCount++;
		}   
	}   
	return nCount;	
}
//
//int CARCListCtrl::GetCurSel() const
//{
//	return 0;
//}

BOOL CGTDListCtrl::OnEndlabeledit( NMHDR* pNMHDR, LRESULT* pResult )
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	LV_ITEM* plvItem = &pDispInfo->item;
	if(plvItem)
	{		
		if(mpEditImpl)
			mpEditImpl->OnDoneEdit(*this, plvItem->iItem,plvItem->iSubItem);
	}

	return TRUE;
}

//CGTDListCtrl::ItemImplMap* CGTDListCtrl::GetImplMap( int nItem )
//{
//	ItemImplMap* itemdata = (ItemImplMap*)GetItemData(nItem);
//	if(std::find(m_vItemMapList.begin(),m_vItemMapList.end(),itemdata)==m_vItemMapList.end())
//	{
//		itemdata = new ItemImplMap;
//		SetItemData(nItem,(DWORD_PTR)itemdata);
//		m_vItemMapList.push_back(itemdata);
//	}
//	return itemdata;
//}
//
//CGTDListCtrl::ItemImplMap* CGTDListCtrl::GetImplMap( int nItem ) const
//{
//	ItemImplMap* itemdata = (ItemImplMap*)GetItemData(nItem);
//	if(std::find(m_vItemMapList.begin(),m_vItemMapList.end(),itemdata)==m_vItemMapList.end())
//	{
//		itemdata = NULL;
//	}
//	return itemdata;
//}
//
//void CGTDListCtrl::Clear()
//{
//	for (size_t i=0;i< m_vItemMapList.size();++i)
//	{
//		delete m_vItemMapList[i];
//	}
//	m_vItemMapList.clear();
//}

void CGTDListCtrl::OnLButtonDblClk( UINT nFlags, CPoint point )
{
	// get the click column
	int index;
	int column;
	if((index = HitTestEx(point, &column)) != -1)
	{
		//ListCtrlItemImpl* pImpl = GetItemImpl(index,column);
		if(mpEditImpl)
			mpEditImpl->DblClickItem(*this, index, column);
	}
	__super::OnLButtonDblClk(nFlags, point);
}

BOOL CGTDListCtrl::OnClickColumn( NMHDR* pNMHDR, LRESULT* pResult )
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	LV_ITEM* plvItem = &pDispInfo->item;
	if(plvItem)
	{
		//m_lastSelItem = plvItem->iItem;
		//m_lastSelSubItem = plvItem->iSubItem;
	}
	return TRUE;
}

void CGTDListCtrl::SelectItem( int nItem )
{
	if(nItem<GetItemCount() && nItem>=0)
	{
		UnSelectItem();
		//SetHotItem(nItem);
		//::SendMessage(GetSafeHwnd(),LB_SETSEL,nItem,nItem); 
		SetFocus(); 
		SetItemState(nItem,    LVIS_SELECTED   |   LVIS_FOCUSED,   LVIS_SELECTED   |   LVIS_FOCUSED); 
		//SetHotItem(nItem);
		EnsureVisible(nItem,   FALSE); 
		::SendMessage(m_hWnd,   LVM_SETEXTENDEDLISTVIEWSTYLE, 
			LVS_EX_FULLROWSELECT,   LVS_EX_FULLROWSELECT);
	}
}

CGTDListCtrl::CGTDListCtrl()
{
	//m_lastSelSubItem = m_lastSelSubItem = -1;
	mpEditImpl = NULL;
}

CGTDListCtrl::~CGTDListCtrl()
{
	//Clear();
	//ClearMangerList();
	cpputil::autoptr_reset(mpEditImpl);
}

//void CGTDListCtrl::ClearMangerList()
//{
//	for(size_t i=0;i<m_vManageImpList.size();++i)
//		delete m_vManageImpList[i];
//	m_vManageImpList.clear();
//}
//
//void CGTDListCtrl::AddManageImp( ListCtrlItemImpl* pImpl )
//{
//	if( std::find(m_vManageImpList.begin(),m_vManageImpList.end(),pImpl)!=m_vManageImpList.end() )
//		return;
//	m_vManageImpList.push_back(pImpl);
//}

void CGTDListCtrl::InitStyle()
{	
	ModifyStyle(LVS_SINGLESEL | LVS_EDITLABELS, 0);
	DWORD dwStyle = GetExtendedStyle();
	dwStyle |= LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_GRIDLINES;
	SetExtendedStyle(dwStyle);
}

void CGTDListCtrl::setImpl( ListCtrlItemImpl* pImpl )
{
	cpputil::autoptr_reset(mpEditImpl,pImpl);
	if(pImpl)
		pImpl->OnSetToCtrl(*this);
}


int CGTDListCtrl::EnLargeItemCount( int nCount )
{
	int orignCount = GetItemCount();
	if(nCount>orignCount)
	{
		for(int i = orignCount;i<nCount;i++)
		{
			InsertItem(i,_T(""));
		}
	}
	return GetItemCount();
}

void CGTDListCtrl::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{

	if(mpEditImpl)
	{
		mpEditImpl->OnChar(*this,nChar,nRepCnt,nFlags);		
	}
	if(nChar == VK_ESCAPE && GetParent()->GetFocus()==this)
	{
		GetParent()->SetFocus();
	}
	__super::OnChar(nChar,nRepCnt,nFlags);
}

bool CGTDListCtrl::GetCurSelect( int& index ) const
{
	IntList ilist;
	if(GetSelectedItems(ilist))
	{
		index = *ilist.begin();
		return true;
	}
	return false;
}

BOOL CGTDListCtrl::PreTranslateMessage( MSG* pMsg )
{
	if( pMsg->message == WM_KEYDOWN )
	{
		if(pMsg->wParam == VK_RETURN
			|| pMsg->wParam == VK_DELETE
			|| pMsg->wParam == VK_ESCAPE
			|| GetKeyState( VK_CONTROL)
			)
		{
			::TranslateMessage(pMsg);
			::DispatchMessage(pMsg);
			return true;   // DO NOT process further
		}
	}

	return __super::PreTranslateMessage(pMsg);
}

void CGTDListCtrl::UnSelectItem()
{
	POSITION   pos   =   GetFirstSelectedItemPosition();   
	if   (pos   ==   NULL)   
		TRACE0("No   items   were   selected!\n");   
	else   
	{   
		while   (pos)   
		{   
			int   nItem   =   GetNextSelectedItem(pos);   
			SetItemState(nItem, 0,-1);
		}   
	}   
	
}



CComboBox* ListCtrlItemImpl::ShowInPlaceList( CGTDListCtrl& ctrl,int nItem, int nCol ,const CStringList& strList)
{
	// The returned pointer should not be saved

	// Make sure that the item is visible
	if(!ctrl.EnsureVisible(nItem, TRUE)) 
		return NULL;

	// Make sure that nCol is valid 
	CHeaderCtrl* pHeader = ctrl.GetHeaderCtrl();
	int nColumnCount = pHeader->GetItemCount();
	if(nCol >= nColumnCount || ctrl.GetColumnWidth(nCol) < 10)
		return NULL;

	// Get the column offset
	int offset = 0;
	for(int i = 0; i < nCol; i++)
		offset += ctrl.GetColumnWidth(i);

	CRect rect;
	ctrl.GetItemRect(nItem, &rect, LVIR_BOUNDS);

	// Now scroll if we need to expose the column
	CRect rcClient;
	ctrl.GetClientRect(&rcClient);
	if(offset + rect.left < 0 || offset + rect.left > rcClient.right)
	{
		CSize size;
		size.cx = offset + rect.left;
		size.cy = 0;
		ctrl.Scroll(size);
		rect.left -= size.cx;
	}
	rect.left += (offset + 4);
	rect.right = rect.left + ctrl.GetColumnWidth(nCol) - 3;
	int height = rect.bottom - rect.top;
	rect.bottom += (10 * height);
	if(rect.right > rcClient.right) 
		rect.right = rcClient.right;

	DWORD dwStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_DROPDOWNLIST|CBS_DISABLENOSCROLL;


	//CStringList& strList = ((LVCOLDROPLIST*)ddStyleList[nCol])->List;
	CString csSelStr = ctrl.GetItemText( nItem, nCol );
	POSITION pos;
	int i = 0;
	int nSelIndex = 0;
	for( pos = strList.GetHeadPosition(); pos; i++ )
	{

		CString csStr = strList.GetAt( pos );
		if( csStr == csSelStr )
		{
			nSelIndex = i;
			break;
		}
		strList.GetNext( pos );
	}	

	return NULL;
}


